package main

import (
	"fmt"
)

func printSlice(element []int32, str string) {
	fmt.Printf("%s, len = %d, cap = %d, slice = %v \n", str, len(element), cap(element), element)
}

func main() {
	//长度满了，容量满了
	var arr1 []int32 = []int32{5, 6, 7, 8, 9}
	//直接赋值，当前为浅拷贝，没有脱钩
	var arr2 []int32 = arr1
	//深拷贝
	var arr3 []int32 = make([]int32, 5, 5)
	copy(arr3, arr1)
	//深拷贝
	var arr4 []int32 = make([]int32, 5, 10)
	copy(arr4, arr1)
	//指针赋值，当前浅拷贝，没有脱钩
	var arr5 *[]int32 = &arr1

	printSlice(arr1, "arr1")
	printSlice(arr2, "arr2")
	printSlice(arr3, "arr3")
	printSlice(arr4, "arr4")
	printSlice(*arr5, "arr5")
	fmt.Println()

	//修改
	arr1[0] = 10
	printSlice(arr1, "arr1")
	printSlice(arr2, "arr2")
	printSlice(arr3, "arr3") //深拷贝，所以不改变
	printSlice(arr4, "arr4") //深拷贝，所以不改变
	printSlice(*arr5, "arr5")
	fmt.Println()

	//追加
	arr1 = append(arr1, 4)
	printSlice(arr1, "arr1")
	printSlice(arr2, "arr2") //脱钩，arr2与arr1指向的地址当前不一致
	printSlice(arr3, "arr3") //深拷贝，所以不改变
	printSlice(arr4, "arr4") //深拷贝，所以不改变
	printSlice(*arr5, "arr5")
	fmt.Println()

	//追加
	arr1 = append(arr1, 3, 2, 1, 0, -1)
	printSlice(arr1, "arr1")
	printSlice(arr2, "arr2") //脱钩，arr2与arr1指向的地址当前不一致
	printSlice(arr3, "arr3") //深拷贝，所以不改变
	printSlice(arr4, "arr4") //深拷贝，所以不改变
	printSlice(*arr5, "arr5")
	fmt.Println()

	//
	//
	//
	//
	//长度没满，容量没满
	var arr1a []int32 = make([]int32, 5, 10)
	arr1a[0] = 1
	arr1a[1] = 2
	arr1a[2] = 3
	arr1a[3] = 4
	arr1a[4] = 5
	//直接赋值，当前为浅拷贝，没有脱钩
	/*
		arr2a切片初始化的表面结果是长度=5，容量=10，元素填充了5个
		底层结果，是，arr2a这个变量记住了arr1a的前5个元素状态
		可以通过arr2a快速获取arr1a前5个元素的状态信息，但是arr1a第6个元素就获取不到
	*/
	var arr2a []int32 = arr1a
	//深拷贝
	var arr3a []int32 = make([]int32, 5, 5)
	copy(arr3a, arr1a)
	//深拷贝
	var arr4a []int32 = make([]int32, 5, 10)
	copy(arr4a, arr1a)
	//指针赋值，当前浅拷贝，没有脱钩
	var arr5a *[]int32 = &arr1a

	printSlice(arr1a, "arr1a")
	printSlice(arr2a, "arr2a")
	printSlice(arr3a, "arr3a")
	printSlice(arr4a, "arr4a")
	printSlice(*arr5a, "arr5a")
	fmt.Println()

	//修改
	arr1a[0] = 10
	printSlice(arr1a, "arr1a")
	printSlice(arr2a, "arr2a")
	printSlice(arr3a, "arr3a") //深拷贝，所以不改变
	printSlice(arr4a, "arr4a") //深拷贝，所以不改变
	printSlice(*arr5a, "arr5a")
	fmt.Println()

	//追加
	arr1a = append(arr1a, 6)
	printSlice(arr1a, "arr1a") //append()操作更新arr1a切片的长度，从5到6
	printSlice(arr2a, "arr2a") //arr2a切片的长度仍然是5，没有代码更新arr2a切片的长度，所以脱钩。但此时arr2a与arr1a共享同一个底层数组
	printSlice(arr3a, "arr3a") //深拷贝，所以不改变
	printSlice(arr4a, "arr4a") //深拷贝，所以不改变
	printSlice(*arr5a, "arr5a")
	fmt.Println()
	//此时arr2a与arr1a共享同一个底层数组
	arr2a = arr2a[:10] //手动更新arr2a的长度为10
	var length int = len(arr2a)
	var i int = 0
	for i = 0; i < length; i++ {
		fmt.Printf("arr2a[%d] = %d \n", i, arr2a[i]) //会打印出索引5元素
	}
	fmt.Println()

	//追加
	arr1a = append(arr1a, 7, 8, 9, 10, -1) //触发扩容，底层数组变动
	arr1a[0] = 11                          //新数组的第一个元素更新
	printSlice(arr1a, "arr1a")
	printSlice(arr2a, "arr2a") //脱钩，arr2a与arr1a指向的地址当前不一致，分别指向2个不同数组
	printSlice(arr3a, "arr3a") //深拷贝，所以不改变
	printSlice(arr4a, "arr4a") //深拷贝，所以不改变
	printSlice(*arr5a, "arr5a")
	fmt.Println()

	for i = 0; i < length; i++ {
		fmt.Printf("arr2a[%d] = %d \n", i, arr2a[i])
	}
	fmt.Println()

	/*
		切片的访问范围由其长度（len）决定，而不是由底层数组的容量决定。
		虽然 arr1a 和 arr2a 共享同一个底层数组，但 arr2a 的长度是 5，因此它只能访问索引 [0, 4] 的元素，无法访问索引 5。
		这是因为 Go 的切片设计中，访问元素时会检查索引是否超出切片的长度范围（0 <= index < len）。
		即使底层数组中有更多的元素，切片也只能访问其长度范围内的元素。
	*/
}
